package threshold;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import dao.OutputFile;

import evaluation.EvaluationTool;

public class MaxNDCRThresholdFinder {
	
	private String ndcrFile;
	public List<String> initialize(List<String> args) {
		ndcrFile = args.size() > 0 ? args.get(0) : null;
		return args;
	}
	
	protected static PairComparator comp = new PairComparator();
	
	public double find(List<Integer> label, List<Double> predicted) {
		List<Pair> pairList = getPairs(label, predicted);
		Collections.sort(pairList, comp);
		
		double hrs = getHour(label.size());
		double gel = getAverageEventLength(label);
		double hours = hrs * gel;
		
		List<Double> ndcrList = getNdcrList(pairList, hours);
		
		if(ndcrFile != null) {
			printNDCR(ndcrFile, ndcrList, pairList);
		}
		
		return findThreshold(pairList, ndcrList);
	}
	
	public double getHour(int size) {
		return size * 15 / (double) (25 * 3600);
	}
	
	public double getAverageEventLength(List<Integer> label) {
		int state = 0;
		int count = 0;
		int size = 0;
		for(int l : label) {
			if(state == 0) {
				if(l == 1) {
					count ++;
					state = 1;
				}
			} else {
				if(l == 0) {
					state = 0;
				}
			}
			
			if(l == 1) {
				size ++;
			}
		}
		
		double ratio = count == 0 ? 1 : size / (double) count;
		return ratio;
	}
	
	protected void printNDCR(String filename, List<Double> ndcrList, List<Pair> pairList) {
		OutputFile fout = new OutputFile();
		fout.open(filename);
		
		Iterator<Pair> pItr = pairList.iterator();
		for(double ndcr : ndcrList) {
			Pair pair = pItr.next();
			fout.write(pair.label + "\t" + pair.logProb + "\t" + ndcr + "\n");
		}
		fout.close();		
	}
	
	protected List<Double> getNdcrList(List<Pair> pairList, double hours) {
		int tp = 0;
		int tn = 0;
		int fp = 0;
		int fn = 0;
		
		// initialize to "saying nothing"
		for(Pair pair : pairList) {
			if(pair.label == 1) {
				fp ++;
			} else {
				tn ++;
			}
		}
		
		// compute ndcr
		List<Double> ndcrList = new ArrayList<Double>();
		for(Pair pair : pairList) {
			int l = pair.label;
			
			if(l == 1) {
				fp --;
				tp ++;
			} else {
				tn --;
				fn ++;
			}
			
			double ndcr = EvaluationTool.getNDCR(tp, tn, fp, fn, hours);
			ndcrList.add(ndcr);
		}
		
		return ndcrList;
	}
	
	protected double findThreshold(List<Pair> pairList, List<Double> ndcrList) {

		Pair bestPair = null;
		double bestNDCR = Double.POSITIVE_INFINITY;
		int place = 0;
		for(int i = 0; i < pairList.size(); i++) {
			double ndcr = ndcrList.get(i);
			if(ndcr < bestNDCR) {
				bestPair = pairList.get(i);
				bestNDCR = ndcr;
				place = i;
			}
		}
		
		System.out.println("best prob = " + bestPair.logProb + "\tbest ncdr = " + bestNDCR + "\tplace=" + place);
		
		return bestPair.logProb;
	}
	
	protected List<Pair> getPairs(List<Integer> label, List<Double> predicted) {
		Iterator<Integer> lItr = label.iterator();
		Iterator<Double> pItr = predicted.iterator();
		
		List<Pair> pairList = new ArrayList<Pair>(label.size());
		
		while(lItr.hasNext()) {
			Pair pair = new Pair();
			pair.label = lItr.next();
			pair.logProb = pItr.next();
			pairList.add(pair);
		}
		
		return pairList;
	}
	
	protected static class Pair {
		public int label;
		public double logProb;
		
		@Override
		public String toString() {
			return label + " " + logProb;
		}
	}
	
	private static class PairComparator implements Comparator<Pair> {
		@Override
		public int compare(Pair arg0, Pair arg1) {
			return - Double.compare(arg0.logProb, arg1.logProb);
		}
	}
}
